Glass Effect Transition

This document provides a comprehensive explanation of Glass Effect Transitions in Scripting, including how Liquid Glass materials animate during view changes, how geometry matching works, and how to correctly use NamespaceReader to access SwiftUI’s @Namespace within TSX code.

Contents include:

  • Overview of Liquid Glass transitions
  • The three transition types
  • Relationship among glassEffectTransition, glassEffectID, and namespace
  • Role of glassEffectUnion
  • Purpose and behavior of GlassEffectContainer
  • Design and usage of NamespaceReader
  • Detailed walkthrough of the provided example
  • Best practice recommendations

1. Overview: What Is a Glass Effect Transition?

A Glass Effect Transition defines how a Liquid Glass material animates when:

  • A view is inserted or removed
  • Layout changes
  • Views switch between two states
1type GlassEffectTransition = 'identity' | 'materialize' | 'matchedGeometry'

These transitions affect only the Liquid Glass material—not the rest of the view’s opacity or scale.

A transition controls:

  1. How the glass material appears or disappears
  2. Whether the shape of the glass participates in animation
  3. Whether the glass attempts to match geometry with other shapes

2. Transition Types

2.1 identity

1glassEffectTransition="identity"

Behavior:

  • No animation or geometry change.
  • The glass effect appears immediately with no fade or shape transformation.

Use cases:

  • Disabling animations
  • Static UI
  • Debugging transitions

2.2 materialize

1glassEffectTransition="materialize"

Behavior:

  • The material fades in or out smoothly.
  • No attempt is made to match geometry with any other glass shape.
  • Content transitions in a simple, clean way.

Use cases:

  • Basic menu transitions
  • Buttons appearing or disappearing
  • When geometric continuity is not needed

2.3 matchedGeometry (most powerful)

1glassEffectTransition="matchedGeometry"

Behavior:

  • The Liquid Glass shape morphs between views that share the same ID and namespace.
  • Creates smooth, fluid transitions between corresponding glass shapes.
  • Requires glassEffectID and namespace.

Use cases:

  • Menu switching (e.g., Edit → Home)
  • Toolbar reconfiguration
  • Any UI element where continuity matters

3. glassEffectID and namespace

The core of geometric matching

Liquid Glass’ geometric-matching transitions require the ability to identify and relate specific glass shapes.


3.1 Why IDs Are Required

To animate a shape from state A → state B, the system must know:

  • which old shape matches which new shape

The identity is provided by:

1glassEffectID={{
2  id: 1,
3  namespace
4}}

Views with the same id in the same namespace are treated as the same conceptual glass entity across states.


3.2 Why a namespace Is Required

SwiftUI’s matchedGeometry system requires an @Namespace to define the animation scope.

Since TSX cannot define SwiftUI property wrappers, Scripting provides:

1<NamespaceReader>
2  {namespace => ()}
3</NamespaceReader>

Inside the closure:

  • namespace refers to a real SwiftUI @Namespace
  • All glassEffectID and glassEffectUnion inside this closure must use this namespace

Benefits:

  • Provides correct scope for geometry transitions
  • Prevents accidental cross-scope animation
  • Ensures matchedGeometry and unions behave predictably

Without a namespace, geometric matching does not work.


4. glassEffectUnion: Unifying Glass Regions

glassEffectUnion merges multiple views into a single continuous glass material region.

1glassEffectUnion={{
2  id: 1,
3  namespace
4}}

Effects:

  • Buttons appear to share a single underlying piece of glass
  • Material may shift or reflow cohesively
  • Enhances visual coherence in grouped UI elements

Typically paired with matchedGeometry transitions.


5. GlassEffectContainer

The container provides:

  • A shared environment for geometry matching
  • A rendering boundary for unioned glass
  • Optimized rendering for clusters of Liquid Glass views

Example:

1<GlassEffectContainer>
2  <HStack> ... </HStack>
3</GlassEffectContainer>

Every view participating in glass transitions should be placed inside the same container.


6. NamespaceReader

Exposing SwiftUI’s @Namespace to TSX

6.1 Why NamespaceReader Exists

SwiftUI defines matchedGeometry transitions using:

1@Namespace private var namespace

But TSX code cannot create Swift @Namespace values. Therefore Scripting provides:

1<NamespaceReader>
2  {namespace => ()}
3</NamespaceReader>

Purpose:

  • Internally creates and manages a real SwiftUI @Namespace
  • Makes the namespace accessible to JavaScript/TypeScript
  • Ensures all participating views share the same namespace
  • Enables matchedGeometry transitions to work in TSX

6.2 How It Works

  • NamespaceReader creates a SwiftUI view containing @Namespace.
  • That namespace is passed to the TSX children via a function parameter.
  • All glassEffectID and glassEffectUnion must use this namespace.
  • All participating views inside the closure are guaranteed to match within the same namespace.

7. Example Analysis

Below is the provided example, demonstrating a dynamic menu switching between two states:

  • Menu A: Home / Settings
  • Menu B: Edit / Erase / Delete
  • Using animation for transitions
  • Using matchedGeometry via ID sharing
  • Using union IDs for continuous material appearance

Key excerpts:

1isAlternativeMenu.value
2  ? <>
3      <Button
4        title="Home"
5        glassEffectID={{id:1, namespace}}
6        glassEffectUnion={{id:1,namespace}}
7      />
8      <Button
9        title="Settings"
10        glassEffectID={{id:2, namespace}}
11        glassEffectUnion={{id:1,namespace}}
12      />
13    </>
14  : <>
15      <Button
16        title="Edit"
17        glassEffectID={{id:1, namespace}}
18        glassEffectUnion={{id:1,namespace}}
19      />
20      <Button
21        title="Erase"
22        glassEffectID={{id:3, namespace}}
23        glassEffectUnion={{id:1,namespace}}
24        glassEffectTransition="materialize"
25      />
26      <Button
27        title="Delete"
28        glassEffectID={{id:2, namespace}}
29        glassEffectUnion={{id:1,namespace}}
30      />
31    </>

1. Shared union (id = 1)

All buttons belong to the same glass union. This produces a smooth, unified underlying glass region.

2. Shared glassEffectID for corresponding buttons

  • Home and Edit share id = 1
  • Settings and Delete share id = 2

→ They animate between each other using matchedGeometry.

3. “Erase” uses a different transition

1glassEffectTransition="materialize"

This button fades its material rather than matching geometry, making its appearance more distinct.

4. Animation is triggered explicitly

1withAnimation(() => {
2  isAlternativeMenu.setValue(
3    !isAlternativeMenu.value
4  )
5})

Glass transitions attach themselves to this animation transaction automatically.


8. Best Practices

1. Use a single GlassEffectContainer

All participating glass views must share one container.

2. Use one NamespaceReader per animated region

Do not create multiple namespaces unless intentionally separating animation scopes.

3. Use consistent glassEffectID between states

Both old and new states must contain the same ID to animate geometrically.

4. Use glassEffectUnion for cohesive material appearance

Especially in toolbars and menus.

5. Prefer matchedGeometry for sophisticated transitions

Use materialize only for elements needing simple appearance behavior.


9. Summary

Glass Effect Transitions enable highly expressive and fluid animations for Liquid Glass materials in iOS 26. In Scripting:

  • glassEffectTransition defines how the material animates
  • glassEffectID and namespace enable geometric matching
  • glassEffectUnion creates unified material regions
  • GlassEffectContainer manages the animation environment
  • NamespaceReader exposes SwiftUI’s @Namespace to TSX, making advanced animations possible